﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.XtraTreeList.Nodes;
using DevExpress.XtraSplashScreen;
using CP.Utility;
using System.IO;
using System.Reflection;
using DevExpress.XtraBars;
using CP.Entities;
using System.Collections;
using CP.Controllers.GPM;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Columns;

namespace GPM
{
    public partial class FrmWebpartDraw : BaseCommForm
    {
        public FrmWebpartDraw()
        {
            InitializeComponent();
            this.BarComponents = components;
            InitializeTreeView();
        }
        private void InitializeTreeView()
        {
            DevExpress.XtraTreeList.Columns.TreeListColumn treeColMenu = new DevExpress.XtraTreeList.Columns.TreeListColumn();
            treeColMenu.Caption = "名称";
            treeColMenu.FieldName = "btn_name";
            treeColMenu.MinWidth = 49;
            treeColMenu.Name = "treeColName";
            treeColMenu.OptionsColumn.AllowEdit = false;
            treeColMenu.OptionsColumn.AllowMove = false;
            treeColMenu.OptionsColumn.AllowMoveToCustomizationForm = false;
            treeColMenu.OptionsColumn.ReadOnly = true;
            treeColMenu.OptionsColumn.ShowInCustomizationForm = false;
            treeColMenu.Visible = true;
            treeColMenu.VisibleIndex = 0;

            DevExpress.XtraTreeList.Columns.TreeListColumn treeColID = new DevExpress.XtraTreeList.Columns.TreeListColumn();
            treeColID.Caption = "ID";
            treeColID.FieldName = "btn_id";
            treeColID.MinWidth = 49;
            treeColID.Name = "treeColID";
            treeColID.OptionsColumn.AllowEdit = false;
            treeColID.OptionsColumn.AllowMove = false;
            treeColID.OptionsColumn.AllowMoveToCustomizationForm = false;
            treeColID.OptionsColumn.ReadOnly = true;
            treeColID.OptionsColumn.ShowInCustomizationForm = false;

            treeColID.Visible = false;
            treeColID.VisibleIndex = 1;

            treeAssembly.treeView.Columns.AddRange(new DevExpress.XtraTreeList.Columns.TreeListColumn[] {
            treeColID,treeColMenu});
            treeAssembly.treeView.OptionsView.ShowColumns = false;
        }

        private void FrmWebpartDraw_Load(object sender, EventArgs e)
        {
            dlg.Filter = ".NET assemblies|*.dll;*.exe";
            dlg.RestoreDirectory = true;
            dlg.Multiselect = false;

        }

        private void btnOpenFile_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            try
            {
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    treeAssembly.treeView.Nodes.Clear();
                    SplashScreenManager.ShowForm(typeof(SplashScreenProgressBar));
                    if (string.IsNullOrEmpty(dlg.FileName))
                        return;
                    string filename = Path.GetFileName(dlg.FileName);
                    string nameSpace = Path.GetFileNameWithoutExtension(filename);
                    if (string.IsNullOrEmpty(nameSpace))
                        return;
                    treeAssembly.treeView.BeginUnboundLoad();
                    OpenAssembly(nameSpace);
                    treeAssembly.treeView.EndUnboundLoad();
                    //treeAssembly.treeView.ExpandAll();
                    SplashScreenManager.CloseForm();
                }
            }
            catch (Exception ex)
            {
                SplashScreenManager.CloseForm();
                ExMessageBox.Show(ex.Message, AppSetter.SoftName);
            }
        }

        private void OpenAssembly(string nameSpace)
        {
            Assembly asm = Assembly.Load(nameSpace);
            Type[] types = asm.GetTypes();
            IEnumerable<Type> formTypes = types.Where<Type>(t => t.BaseType.Name.ToUpper().Contains("FORM")).OrderBy(t => t.FullName);
            FindChildControl(asm, nameSpace, formTypes);
        }

        private void FindChildControl(Assembly asm, string nameSpace, IEnumerable<Type> formTypes)
        {
            if (IsExistNode(treeAssembly.treeView.Nodes, nameSpace))
                return;
            TreeListNode node = treeAssembly.treeView.AppendNode(
                new object[] { nameSpace, nameSpace }, -1, -1, -1, 2);

            Dictionary<string, Dictionary<string, string>> simpleBtns = new Dictionary<string, Dictionary<string, string>>();
            int i = 0;
            foreach (Type type in formTypes)
            {
                Dictionary<string, string> btns = new Dictionary<string, string>();
                Form form = asm.CreateInstance(type.FullName) as Form;
                //append form name node to the root node(namespace node)
                TreeListNode formNode = treeAssembly.treeView.AppendNode(new object[] { form.Name, form.Text },
                                                                                node.Id, -1, -1, 3);
                //append button list node to the form name node
                TreeListNode buttonListNode = treeAssembly.treeView.AppendNode(new object[] { "button list root", "按钮列表" }, formNode.Id, -1, -1, 4);
                FindChildButtons(btns, form);
                FindChildBarItems(btns, form);
                //append button node to the button list node
                foreach (KeyValuePair<string, string> pair in btns)
                {
                    TreeListNode btnNode = treeAssembly.treeView.AppendNode(new object[] { pair.Key, pair.Value },
                        buttonListNode.Id, -1, -1, 5);
                }

                //append column list root node to the form node
                TreeListNode columnListNode = treeAssembly.treeView.AppendNode(new object[] { "column list root", "字段列表" }, formNode.Id, -1, -1, 6);
                //the dictionary of storing the gridcontrol name and coumn names
                Dictionary<string, Dictionary<string, string>> colNames = new Dictionary<string, Dictionary<string, string>>();
                //extract gridcontrol columns to the dictionary
                ExtractXtraGridColumns(colNames, form);
                //iterate the dictionary
                foreach (KeyValuePair<string, Dictionary<string, string>> grid in colNames)
                {
                    string gridName = grid.Key.Substring(0, grid.Key.IndexOf(','));
                    string viewCaption = gridName;
                    if (grid.Key.Length > grid.Key.IndexOf(',') + 1)
                        viewCaption = grid.Key.Substring(grid.Key.IndexOf(',') + 1);
                    //apprend grid name to the column list node
                    TreeListNode gridNameNode = treeAssembly.treeView.AppendNode(new object[] { gridName, viewCaption }, columnListNode.Id, -1, -1, 7);
                    //iterate the grid's column list dictionary
                    foreach (KeyValuePair<string, string> column in grid.Value)
                    {
                        //append the grid's column to the grid node
                        treeAssembly.treeView.AppendNode(new object[] { column.Key, column.Value }, gridNameNode.Id, -1, -1, 8);
                    }
                }

                SplashScreenManager.Default.SendCommand(
                                SplashScreenProgressBar.SplashScreenCommand.SetProgress,
                                (i + 1) * 100 / formTypes.Count());
                i++;
            }
        }

        /// <summary>
        /// extract form's gridcontrol for getting gridview's columns
        /// </summary>
        /// <param name="colNames">output parameter:store the gridcontrols' column name and caption</param>
        /// <param name="form">input parameter:the form name to extract</param>
        private static void ExtractXtraGridColumns(Dictionary<string, Dictionary<string, string>> colNames, Control form)
        {
            foreach (Control control in form.Controls)
            {
                GridControl grid = control as GridControl;
                if (null != grid)
                {
                    GridView gridview = grid.MainView as GridView;
                    if (null != gridview)
                    {
                        Dictionary<string, string> colDict = new Dictionary<string, string>();
                        foreach (GridColumn col in gridview.Columns)
                        {
                            colDict.Add(col.Name, col.Caption);
                        }

                        if (colDict.Count > 0)
                        {
                            colNames.Add(grid.Name + "," + grid.MainView.ViewCaption, colDict);
                        }
                    }
                }
                else
                    ExtractXtraGridColumns(colNames, control);
            }
        }

        private static void FindChildButtons(Dictionary<string, string> names, Control form)
        {
            foreach (Control control in form.Controls)
            {
                SimpleButton sbtn = control as SimpleButton;
                if (null != sbtn)
                    names.Add(sbtn.Name, sbtn.Text);
                Button btn = control as Button;
                if (null != btn)
                    names.Add(btn.Name, btn.Text);
                FindChildButtons(names, control);
            }
        }
        /// <summary>
        ///extract barbuttonitem in barmanager
        ///first get barmanager's container that the private field components
        ///then iterate the container's components, cast to BarManager and 
        ///iterate the barmanager's items, add to button names dictionary
        /// </summary>
        /// <param name="names"></param>
        /// <param name="form"></param>
        private static void FindChildBarItems(Dictionary<string, string> names, Control form)
        {
            FieldInfo fieldInfo = form.GetType().GetField("components", BindingFlags.Instance | BindingFlags.NonPublic);
            IContainer parent = (IContainer)fieldInfo.GetValue(form);
            if (parent == null) return;
            foreach (Component c in parent.Components)
            {
                BarManager barManager = c as BarManager;
                if (null != barManager)
                {
                    foreach (BarButtonItem item in barManager.Items.OfType<BarButtonItem>())
                    {
                        names.Add(item.Name, item.Caption);
                    }
                }
            }

        }

        private bool IsExistNode(TreeListNodes nodes, string value)
        {
            foreach (TreeListNode node in nodes)
            {
                if (node.GetDisplayText("assembly_name") == value)
                    return true;
                IsExistNode(node.Nodes, value);
            }
            return false;
        }

        private void btnClear_ItemClick(object sender, ItemClickEventArgs e)
        {
            treeAssembly.treeView.Nodes.Clear();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            if (treeAssembly.treeView.Nodes.Count == 0)
            {
                ExMessageBox.Show("没有加载程序集，树节点数为0！", AppSetter.SoftName);
                return;
            }

            if (treeAssembly.treeView.Nodes[0].CheckState == CheckState.Unchecked)
            {
                ExMessageBox.Show("没有选中任何节点，不能保存！", AppSetter.SoftName);
                return;
            }

            Dictionary<string, Dictionary<string, string>> checkNodes = new Dictionary<string, Dictionary<string, string>>();
            Dictionary<string, Dictionary<string, Dictionary<string, string>>> checkedColumns = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
            //iterate the form list, get the checked buttons
            GetCheckedIndeterminateNodes(treeAssembly.treeView.Nodes[0].Nodes, checkNodes, checkedColumns);
            splashScreenManager1.ShowWaitForm();
            try
            {
                ModuleController mController = new ModuleController();
                string existsForm = mController.WebpartDraw(txtModuleName.Text.Trim(),
                    treeAssembly.treeView.Nodes[0].GetDisplayText(treeAssembly.treeView.Columns[0]), checkNodes,checkedColumns);
                LogHelper.Log("窗体资源提取", "insert", "保存", txtModuleName.Text);
                splashScreenManager1.CloseWaitForm();
                XtraMessageBox.Show("提示：" + existsForm);
            }
            catch (Exception ex)
            {
                splashScreenManager1.CloseWaitForm();
                XtraMessageBox.Show(ex.Message);
            }
        }

        private void GetCheckedIndeterminateNodes(TreeListNodes nodes, Dictionary<string, Dictionary<string, string>> checkednodes, Dictionary<string, Dictionary<string, Dictionary<string, string>>> checkedColumns)
        {
            DevExpress.XtraTreeList.Columns.TreeListColumn col = treeAssembly.treeView.Columns[0];
            DevExpress.XtraTreeList.Columns.TreeListColumn colName = treeAssembly.treeView.Columns[1];
            foreach (TreeListNode form in nodes)
            {
                //node.Nodes[0] is the form button list node
                if ((form.Nodes[0].CheckState == CheckState.Checked) ||
                    (form.Nodes[0].CheckState == CheckState.Indeterminate))
                {
                    Dictionary<string, string> btns = new Dictionary<string, string>();
                    foreach (TreeListNode btnNode in form.Nodes[0].Nodes)
                    {
                        if ((btnNode.CheckState == CheckState.Checked) ||
                            (btnNode.CheckState == CheckState.Indeterminate))
                        {
                            btns.Add(btnNode.GetValue(col).ToString(), btnNode.GetValue(colName).ToString());
                        }
                    }
                    //concating form name and text as key add to the checked button dictionary
                    if (btns.Count > 0)
                        checkednodes.Add(form.GetValue(col).ToString() + "," + form.GetValue(colName).ToString(), btns);
                }
                //node.Nodes[1] is the form grid list node
                if ((form.Nodes[1].CheckState == CheckState.Checked) ||
                    (form.Nodes[1].CheckState == CheckState.Indeterminate))
                {
                    Dictionary<string, Dictionary<string, string>> checkedGrid = new Dictionary<string, Dictionary<string, string>>();
                    foreach (TreeListNode gridNode in form.Nodes[1].Nodes)
                    {
                        if ((gridNode.CheckState == CheckState.Checked) ||
                            (gridNode.CheckState == CheckState.Indeterminate))
                        {
                            Dictionary<string, string> cols = new Dictionary<string, string>();
                            foreach (TreeListNode colNode in gridNode.Nodes)
                            {
                                if ((colNode.CheckState == CheckState.Checked) ||
                                                            (colNode.CheckState == CheckState.Indeterminate))
                                {
                                    cols.Add(colNode.GetValue(col).ToString(), colNode.GetValue(colName).ToString());
                                }
                            }
                            if (cols.Count > 0)
                                checkedGrid.Add(gridNode.GetValue(col).ToString(), cols);
                        } 
                    }
                    if (checkedGrid.Count > 0)
                        checkedColumns.Add(form.GetValue(col).ToString(), checkedGrid);
                }

            }
        }

    }
}